package ldh.im.fxbase.util;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.StringProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 热点数据单例
 */
public class ImHotMessageSingleton {

    private static final Logger LOGGER = LoggerFactory.getLogger(ImHotMessageSingleton.class);

    private static ImHotMessageSingleton INSTANCE = new ImHotMessageSingleton();
    private Map<Long, AtomicInteger> hotMessageTotalMap = new ConcurrentHashMap<>();
    private Map<Long, IntegerProperty> hotMessageTotalPropertyMap = new HashMap<>();     // 热点消息
    private Map<Long, StringProperty> lastedMessagePropertyMap = new HashMap<>();        // 最新消息

    private ImHotMessageSingleton() {}

    public static ImHotMessageSingleton getInstance() {
        return INSTANCE;
    }

    public void cleanCache() {
        hotMessageTotalPropertyMap.clear();
        lastedMessagePropertyMap.clear();
    }

    public void bindHotMessage(Long sessionId, IntegerProperty hotMessageTotalProperty) {
        LOGGER.info("bind hot message {}", sessionId);
        if (hotMessageTotalPropertyMap.containsKey(sessionId)) {
            IntegerProperty integerProperty = hotMessageTotalPropertyMap.get(sessionId);
            integerProperty.unbind();
        }
        hotMessageTotalPropertyMap.put(sessionId, hotMessageTotalProperty);

        AtomicInteger value = hotMessageTotalMap.putIfAbsent(sessionId, new AtomicInteger(0));
        if (value != null && value.get() > 0) {
            hotMessageTotalProperty.set(value.get());
        }
    }

    public void unBindHotMessage(Long sessionId, IntegerProperty hotMessageTotalProperty) {
        LOGGER.info("unbind hot message {}", sessionId);
        IntegerProperty integerProperty = hotMessageTotalPropertyMap.get(sessionId);
        hotMessageTotalProperty.unbind();
        if (integerProperty == null) { // 后台程序操作热点数据，这个时候，前端可能没有相应的Property
            return;
//            throw new RuntimeException(String.format("%s值不存在", sessionId));
        }
        hotMessageTotalProperty.unbind();
        hotMessageTotalPropertyMap.remove(sessionId);
    }

    public void setHotMessage(Long sessionId, int hotMessageNum) {
        LOGGER.info("setHotMessage sessionId: {}, num: {}", sessionId, hotMessageNum);
        AtomicInteger hotMessageTotal = hotMessageTotalMap.get(sessionId);
        if (hotMessageTotal == null) {
            hotMessageTotal = new AtomicInteger(0);
            hotMessageTotalMap.putIfAbsent(sessionId, hotMessageTotal);
        }
        FxThreadUtil.runLater(()->{
            AtomicInteger hotMessageTotal2 = hotMessageTotalMap.get(sessionId);
            int value = hotMessageTotal2.get();
            hotMessageTotal2.set(hotMessageNum);
            IntegerProperty integerProperty = hotMessageTotalPropertyMap.get(sessionId);
            if (integerProperty != null) {
                integerProperty.set(hotMessageNum);
            }

            if (sessionId > 0L) {
                hotMessageTotalChange(hotMessageNum - value);
            }
        });
    }

    public void incHotMessage(Long sessionId, int hotMessageNum) {
        LOGGER.info("incHotMessage sessionId: {}, num: {}", sessionId, hotMessageNum);
        AtomicInteger hotMessageTotal = hotMessageTotalMap.get(sessionId);
        if (hotMessageTotal == null) {
            hotMessageTotal = new AtomicInteger(0);
            hotMessageTotalMap.putIfAbsent(sessionId, hotMessageTotal);
        }
        FxThreadUtil.runLater(()->{
            AtomicInteger hotMessageTotal2 = hotMessageTotalMap.get(sessionId);
            int total = hotMessageTotal2.addAndGet(hotMessageNum);
            if (total < 0) {
                total = 0;
                hotMessageTotal2.set(total);
            }
            IntegerProperty integerProperty = hotMessageTotalPropertyMap.get(sessionId);
            if (integerProperty != null) {
                integerProperty.set(total);
            }

            if (sessionId > 0) {
                hotMessageTotalChange(hotMessageNum);
            }
        });
    }

    private void hotMessageTotalChange(int hotMessageNum) {
        incHotMessage(0L, hotMessageNum);
    }

    public void bindLastedMessage(Long sessionId, StringProperty lastedMessageProperty) {
        LOGGER.info("bind lasted message {}", sessionId);
        if (lastedMessagePropertyMap.containsKey(sessionId)) {
            StringProperty stringProperty = lastedMessagePropertyMap.get(sessionId);
            stringProperty.unbind();
        }
        lastedMessagePropertyMap.put(sessionId, lastedMessageProperty);
    }

    public void unBindLastedMessage(Long sessionId, StringProperty lastedMessageProperty) {
        LOGGER.info("un bind lasted message {}", sessionId);
        lastedMessagePropertyMap.remove(sessionId);
        lastedMessageProperty.unbind();
    }

    public void changeLastedMessage(Long sessionId, String message) {
        LOGGER.info("change lasted message, sessionId: {}, message: {}", sessionId, message);
        if (lastedMessagePropertyMap.containsKey(sessionId)) {
            StringProperty stringProperty = lastedMessagePropertyMap.get(sessionId);
            FxThreadUtil.runLater(()->{
                stringProperty.set(message);
            });
        }
    }
}
